package com.ndood.admin.repository.system.manager;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Order;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.Selection;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Repository;
import org.springframework.util.StringUtils;

import com.ndood.admin.pojo.system.DepartmentPo;
import com.ndood.admin.pojo.system.RegionPo;
import com.ndood.admin.pojo.system.UserPo;
import com.ndood.admin.pojo.system.dto.UserDto;
import com.ndood.admin.pojo.system.query.UserQuery;

@Repository
public class UserRepositoryManager {
	
	@Autowired
	@PersistenceContext
	private EntityManager entityManager;
	
	/**
	 * 分页查询用户信息
	 */
	public Page<UserDto> pageUserList(UserQuery query) {
		
		// Step1: 初始化参数
		CriteriaBuilder cb = entityManager.getCriteriaBuilder();
		Integer pageSize = query.getLimit();
		Integer pageNo = query.getPageNo();
		
		// Step2: 查询出所有记录
		// cq
		CriteriaQuery<UserDto> cq = cb.createQuery(UserDto.class);
		// root
		Root<UserPo> root = cq.from(UserPo.class);
		// select
		List<Selection<?>> _select = new ArrayList<Selection<?>>() ;
		_select.add(root.get("id"));
		_select.add(root.get("nickName"));
		_select.add(root.get("sex"));
		_select.add(root.get("birthday"));
		_select.add(root.get("headImgUrl"));
		_select.add(root.get("email"));
		_select.add(root.get("mobile"));
		_select.add(root.get("status"));
		_select.add(root.get("createTime"));
		_select.add(root.get("updateTime"));
		_select.add(root.get("address"));
		_select.add(root.<RegionPo>get("province").<Integer>get("sid").alias("provinceId"));
		_select.add(root.<RegionPo>get("city").<Integer>get("sid").alias("cityId"));
		_select.add(root.<RegionPo>get("district").<Integer>get("sid").alias("districtId"));
		_select.add(root.<DepartmentPo>get("department").<Integer>get("id").alias("deptId"));
		_select.add(root.<DepartmentPo>get("department").<Integer>get("name").alias("departmentName"));
		_select.add(root.get("sort"));
		// where
		Predicate _where = computeUserQueryWhere(cb, root, query);
		// order
		List<Order> _order = new ArrayList<Order>();
		_order.add(cb.asc(root.get("sort")));
		// result
		List<UserDto> resultList = entityManager.createQuery(cq.multiselect(_select).where(_where).orderBy(_order))
				.setFirstResult(pageNo * pageSize)
				.setMaxResults(pageSize)
				.setHint("org.hibernate.cacheable", true)
				.getResultList();
		
		// Step3: 查询出总记录数
		// cq
		CriteriaQuery<Long> cqCount = cb.createQuery(Long.class);
		// root
		Root<UserPo> rootCount = cqCount.from(UserPo.class);
		// select
		List<Selection<?>> _selectCount = new ArrayList<Selection<?>>() ;
		_selectCount.add(cb.count(rootCount.get("id")));
		// where
		Predicate _whereCount = computeUserQueryWhere(cb, rootCount, query);
		// result
		Long count = entityManager.createQuery(cqCount.multiselect(_selectCount).where(_whereCount))
				.setHint("org.hibernate.cacheable", true)
				.getSingleResult();
		
		// Step3: 返回结果
		Page<UserDto> page = new PageImpl<>(resultList, new PageRequest(pageNo, pageSize), count);
        return page;
	}

	/**
	 * 创建查询条件
	 */
	private Predicate computeUserQueryWhere(CriteriaBuilder cb, Root<UserPo> root, UserQuery query) {
		String keywords = query.getKeywords();
		Date startTime = query.getStartTime();
		Date endTime = query.getEndTime();
		Integer status = query.getStatus();
		String nickName = query.getNickName();
		Integer deptId = query.getDeptId();
		Integer sex = query.getSex();
		
		Predicate where = cb.conjunction();
		List<Expression<Boolean>> exp = where.getExpressions();
		if (!StringUtils.isEmpty(keywords)) {
			exp.add(cb.like(root.get("nickName"), "%" + keywords + "%"));
		}
		if(status!=null){
			exp.add(cb.equal(root.get("status"), status));
		}
		if(sex!=null){
			exp.add(cb.equal(root.get("sex"), sex));
		}
		if(startTime!=null){
			exp.add(cb.greaterThanOrEqualTo(root.get("createTime"), startTime));
		}
		if(endTime!=null){
			exp.add(cb.lessThan(root.get("createTime"), endTime));
		}
		if(!StringUtils.isEmpty(nickName)){
			exp.add(cb.like(root.get("nickName"), "%" + nickName + "%"));
		}
		if(deptId!=null){
			exp.add(cb.equal(root.<DepartmentPo>get("department").<Integer>get("id"), deptId));
		}
		exp.add(cb.isNotNull(root.<RegionPo>get("province").<Integer>get("id")));
		return where;
	}
}
